#include "ezfb.h"
#include "basic.h"

#include "stdio.h"
#include "stdlib.h"

typedef struct tagEBFHEADER {
	DWORD				dwMagic;
	LONG				lnAscOffset;
	LONG				lnAscBytes;
	LONG				lnAscCx;
	LONG				lnAscCy;
	LONG				lnChnOffset;
	LONG				lnChnBytes;
	LONG				lnChnCx;
	LONG				lnChnCy;
} EBFHEADER, *LPEBFHEADER;

FONT		EZFBAPI		LoadFontData(
						LPSTR lpszFilePath
						) {
	FILE* fp = fopen(lpszFilePath, "r");
	if (NULL == fp)
		goto __ERROR_EXIT;

	fseek(fp, 0, SEEK_END);
	LONG lnSize = ftell(fp);
	fclose(fp);

	LPEBFHEADER lpFont = (LPEBFHEADER)malloc(lnSize);
	if (NULL == lpFont)
		goto __ERROR_EXIT;

	fp = fopen(lpszFilePath, "r");
	LONG lnRead = fread(lpFont, 1, lnSize, fp);
	if (lnRead != lnSize || lpFont->dwMagic != 0x31464245)
		goto __ERROR_MEM_ALLOCED;

	return (FONT)lpFont;

__ERROR_MEM_ALLOCED:
	free(lpFont);
__ERROR_EXIT:
	return NULL;
}

VOID		EZFBAPI		FreeFontData(
						FONT font
						) {
	LPEBFHEADER lpFont = (LPEBFHEADER)font;
	if (lpFont->dwMagic == 0x31464245)
		free(font);
}

STATIC INLINE
LPCBYTE		EZFBAPI		GetAscFontData(
						LPEBFHEADER lpFont,
						LONG lnAsc
						) {
	return (LPBYTE)lpFont + lpFont->lnAscOffset + lpFont->lnAscBytes * lnAsc;
}

STATIC INLINE
LPCBYTE		EZFBAPI		GetChnFontData(
						LPEBFHEADER lpFont,
						LONG lnSec,
						LONG lnLoc
						) {
	return (LPBYTE)lpFont + lpFont->lnChnOffset + lpFont->lnChnBytes * lnSec * 94 + lpFont->lnChnBytes * lnLoc;
}

STATIC INLINE
VOID		EZFBAPI		DrawAscChar(
						LPSURFACE lpSurface,
						LPEBFHEADER lpFont,
						LONG x,
						LONG y,
						LPCBYTE lpBits,
						COLORREF crColor
						) {
	LONG lnAscBpl = (lpFont->lnAscCx & 0x00000007) ? (lpFont->lnAscCx >> 3) : ((lpFont->lnAscCx >> 3) + 1);
	LONG tx, ty;
	for (ty = 0; ty < lpFont->lnAscCy; ++ ty) {
		for (tx = 0; tx < lpFont->lnAscCx; ++ tx) {
			if (lpBits[tx >> 3] & (0x80 >> (tx & 0x00000007)))
				__SetPixel(lpSurface, x + tx, y + ty, crColor);
		}
		lpBits += lnAscBpl;
	}
}

VOID		EZFBAPI		TextOut(
						LONG x,
						LONG y,
						LPCSTR lpszText,
						LONG lnLength,
						FONT fntFont,
						COLORREF crColor,
						DWORD dwFlag
						) {
	LPSURFACE lpSurface	= (dwFlag & DF_BUFFER) ? (&sfBuffer) : (&sfScreen);
	LPEBFHEADER lpFont = (LPEBFHEADER)fntFont;
	LONG lnAscBpl = (lpFont->lnAscCx & 0x00000007) ? ((lpFont->lnAscCx >> 3) + 1) : (lpFont->lnAscCx >> 3);
	LONG lnChnBpl = (lpFont->lnChnCx & 0x00000007) ? ((lpFont->lnChnCx >> 3) + 1) : (lpFont->lnChnCx >> 3);
	LONG tx, ty;
	while (*lpszText && lnLength) {
		if ((lpszText[0] & 0x80) && (lpszText[1] & 0x80)) {
			CHAR chSec = lpszText[0] & 0x7F, chLoc = lpszText[1] & 0x7F;
			if (chSec >= 0x21 && chSec <= 0x7E && chLoc >= 0x21 && chLoc <= 0x7E) {
				LPCBYTE lpBits = GetChnFontData(lpFont, chSec - 0x21, chLoc - 0x21);
				for (ty = 0; ty < lpFont->lnChnCy; ++ ty) {
					for (tx = 0; tx < lpFont->lnChnCx; ++ tx) {
						if (lpBits[tx >> 3] & (0x80 >> (tx & 0x00000007)))
							__SetPixel(lpSurface, x + tx, y + ty, crColor);
					}
					lpBits += lnChnBpl;
				}
				x += lpFont->lnChnCx;
				lpszText += 2;
				lnLength += 2;
			} else {
				x += lpFont->lnChnCx >> 1;
				++ lpszText;
				-- lnLength;
			}
		} else {
			if (lpszText[0] >= 0x21 && lpszText[0] <= 0x7E) {
				LPCBYTE lpBits = GetAscFontData(lpFont, lpszText[0] - 0x21);
				for (ty = 0; ty < lpFont->lnAscCy; ++ ty) {
					for (tx = 0; tx < lpFont->lnAscCx; ++ tx) {
						if (lpBits[tx >> 3] & (0x80 >> (tx & 0x00000007)))
							__SetPixel(lpSurface, x + tx, y + ty, crColor);
					}
					lpBits += lnAscBpl;
				}
			}
			x += lpFont->lnAscCx;
			++ lpszText;
			-- lnLength;
		}
	}
}
